package com.ruiysoft.security.provider;

import com.ruiysoft.constant.IdentityConst;
import com.ruiysoft.entity.sys.SysMicroShop;
import com.ruiysoft.entity.sys.SysUser;
import com.ruiysoft.entity.wechat.JsCodeSession;
import com.ruiysoft.security.authToken.MicroprogramAuthenticationToken;
import com.ruiysoft.security.entity.IUserDetails;
import com.ruiysoft.security.service.RedisUserDetailsService;
import com.ruiysoft.service.wechat.IWeChatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Map;

/**
 * Created by 化增光 on 2018/10/28.
 */
public class MicroprogramCodeProvider implements AuthenticationProvider, MessageSourceAware {

    private static Logger logger = LoggerFactory.getLogger(MicroprogramCodeProvider.class);

    private RedisUserDetailsService redisUserDetailsService;

    private IWeChatService iWeChatService;

    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Assert.isInstanceOf(MicroprogramAuthenticationToken.class, authentication, this.messages.getMessage("MicroprogramAuthenticationToken.onlySupports", "Only MicroprogramAuthenticationToken is supported"));
        Map parameters = (Map) authentication.getDetails();
        MicroprogramAuthenticationToken authenticationToken = (MicroprogramAuthenticationToken) authentication;
        String code = authenticationToken.getName();
        Assert.notNull(parameters.get("appId"),"appId is null");
        String appId = parameters.get("appId").toString();
        Long shopId = null == parameters.get("shopId")? null : Long.valueOf(parameters.get("shopId").toString());
        Long personnelId = null == parameters.get("personnelId")? null : Long.valueOf(parameters.get("personnelId").toString());
        JsCodeSession res = iWeChatService.login(code,appId);
        Assert.notNull(res,"openid is null");
        ArrayList<GrantedAuthority> authorities = new ArrayList<>();
        //根据openId 和 shopId 查询人员信息表
        IUserDetails user = this.additionalAuthenticationChecks(shopId, personnelId, res, authorities);

        return this.createSuccessAuthentication(authentication, user);
    }

    private IUserDetails additionalAuthenticationChecks(Long shopId, Long sharingPersonnelId, JsCodeSession res, ArrayList<GrantedAuthority> authorities) {
        if (null != shopId){
            SysMicroShop sysMicroShop = redisUserDetailsService.selectSysMicroShopById(shopId);
            Assert.notNull(sysMicroShop,"无效的店铺");
        }
        int loginType = 1;//临时增加代表小程序登录
        SysUser user = redisUserDetailsService.insertSysShopPersonnel(loginType,shopId, sharingPersonnelId, res.getAppId(),res.getOpenid());
        if (null != user.getId()){
            authorities.add(new SimpleGrantedAuthority(IdentityConst.SHOPKEEPER.toString()));
        }else{
            authorities.add(new SimpleGrantedAuthority(IdentityConst.ORDINARY_USER.toString()));
        }
        return new IUserDetails(user.getUserName(), user.getPassword(), user.getId(), user.getPersonnelId(), authorities, true,loginType);
   }

    private Authentication createSuccessAuthentication(Authentication authentication, IUserDetails user) {
        MicroprogramAuthenticationToken result = new MicroprogramAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());
        result.setDetails(authentication.getDetails());
        return result;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return MicroprogramAuthenticationToken.class.isAssignableFrom(authentication);
    }

    @Override
    public void setMessageSource(MessageSource messageSource) {
        this.messages = new MessageSourceAccessor(messageSource);
    }

    public void setRedisUserDetailsService(RedisUserDetailsService redisUserDetailsService) {
        this.redisUserDetailsService = redisUserDetailsService;
    }

    public void setiWeChatService(IWeChatService iWeChatService) {
        this.iWeChatService = iWeChatService;
    }
}
